﻿//using Timer = System.Timers.Timer;

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Threading.Tasks;
using System.Windows.Forms;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using ProxyTool.ControlAnimation;
using ProxyTool.Models;
using ProxyTool.Services;
using ProxyTool.Services.Utils;
using ProxyTool.Setting;
using ProxyTool.Utils;
using ZTn.Json.JsonTreeView;

#region resharper no clear up

using Timer = System.Timers.Timer;

# endregion

namespace ProxyTool.Controls
{
    public partial class ProxyEditControl : UserControl
    {
        private TreeNodeLinkList _currTreeNodeLinklist;
        private Timer _jsonValidationTimer;

        public ProxyEditControl(ProxyData proxyData)
        {
            InitializeComponent();
            if (proxyData == null)
                throw new ArgumentException("proxy is null");
            //设置代理对象
            SetProxy(proxyData);
            //层级优先
            chkLevelPriority.Checked = true;
            //模糊查找
            chkLikeLookup.Checked = true;
            //设置查询按钮状态
            SetQueryButtonStatus();
            //初始化调试
            InitDebug();
        }

        public string ProxyJsonFileName { get; set; }

        /// <summary>
        ///     设置代理对象
        /// </summary>
        private void SetProxy(ProxyData proxyData)
        {
            chkUseDataContract.Checked = proxyData.UseDataContract;
            txtProxyType.Text = proxyData.ProxyType;
            txtRequestDataMaxExpandDepth.Text = proxyData.RequestDataMaxExpandDepth.ToString();
            //树节点
            jTokenTree.SetJsonSource(
                !string.IsNullOrEmpty(proxyData.ProxyJsonString) ? proxyData.ProxyJsonString : "{}");
            //设置首节点为选中节点
            SetSelectedNodeWithTopNode();
        }

        /// <summary>
        ///     获取代理对象数据
        /// </summary>
        /// <returns></returns>
        public ProxyData GetProxyData()
        {
            ProxyData proxyData = new ProxyData();
            proxyData.ProxyType = GetProxyType();
            proxyData.UseDataContract = chkUseDataContract.Checked;
            proxyData.RequestDataMaxExpandDepth = GetRequestDataMaxExpandDepth();
            var jsonString = jTokenTree.jsonTreeView.Nodes[0].Tag.ToString();
            if (!string.IsNullOrEmpty(jsonString))
            {
                var jToken = JsonHelper.ObjectFromJsonString<JToken>(jsonString);
                jsonString = JsonHelper.ObjectToJsonString(jToken, Formatting.None);
            }

            proxyData.ProxyJsonString = jsonString;
            return proxyData;
        }

        /// <summary>
        ///     刷新代理对象
        /// </summary>
        public void RefreshProxy()
        {
            string proxyType = GetProxyType();
            var proxyData =
                ProxyTestService.GetProxyData(proxyType, chkUseDataContract.Checked, GetRequestDataMaxExpandDepth());
            //树节点
            if (proxyData != null && !string.IsNullOrEmpty(proxyData.ProxyJsonString))
                jTokenTree.SetJsonSource(proxyData.ProxyJsonString);
            else
            {
                jTokenTree.SetJsonSource("{}");
            }
        }

        /// <summary>
        ///     重新加载代理对象
        /// </summary>
        private void ReLoadProxy()
        {
            var proxyData = GetProxyData();
            proxyData = ProxyTestService.ReLoadProxy(proxyData);
            if (proxyData != null && !string.IsNullOrEmpty(proxyData.ProxyJsonString))
                jTokenTree.SetJsonSource(proxyData.ProxyJsonString);
            else
            {
                jTokenTree.SetJsonSource("{}");
            }
        }

        /// <summary>
        ///     获取请求类型
        /// </summary>
        /// <returns></returns>
        private string GetProxyType()
        {
            string proxyType = txtProxyType.Text;
            return proxyType.Replace(" ", string.Empty);
        }

        /// <summary>
        ///     获取请求数据最大展开深度
        /// </summary>
        /// <returns></returns>
        private int GetRequestDataMaxExpandDepth()
        {
            int requestDataMaxExpandDepth;
            if (string.IsNullOrWhiteSpace(txtRequestDataMaxExpandDepth.Text))
            {
                txtRequestDataMaxExpandDepth.Focus();
                throw new ProxyToolException("请求数据最大展开深度不能为空");
            }

            var isOk = int.TryParse(txtRequestDataMaxExpandDepth.Text, out requestDataMaxExpandDepth);
            if (!isOk || requestDataMaxExpandDepth <= 0)
                throw new ProxyToolException("请求数据最大展开深度必须为数字且大于0");
            return requestDataMaxExpandDepth;
        }

        /// <summary>
        ///     执行代理请求
        /// </summary>
        private void ProxyTestDo()
        {
            string proxyType = GetProxyType();
            if (string.IsNullOrEmpty(proxyType)) return;
            ProxyData proxyData = GetProxyData();
            string jsonString = ProxyTestService.ProxyTestDo(proxyData);
            if (!string.IsNullOrWhiteSpace(jsonString))
            {
                var jToken = JsonHelper.ObjectFromJsonString<JToken>(jsonString);
                jsonString = JsonHelper.ObjectToJsonString(jToken);
            }

            jsonResultValueTextBox.Text = jsonString;
            jsonValueTabControl.SelectedIndex = 1;
        }

        private void jsonValueTextBox_TextChanged(object sender, EventArgs e)
        {
            StartValidationTimer();
        }

        private void StartValidationTimer()
        {
            _jsonValidationTimer?.Stop();
            _jsonValidationTimer = new Timer(250);
            _jsonValidationTimer.Elapsed += (o, args) =>
            {
                _jsonValidationTimer.Stop();
                jTokenTree.Invoke(new Action(JsonValidationTimerHandler));
            };
            _jsonValidationTimer.Start();
        }

        private void JsonValidationTimerHandler()
        {
            try
            {
                jTokenTree.UpdateSelected(jsonValueTextBox.Text);
                SetJsonStatus("Json format validated.", false);
            }
            catch (JsonReaderException exception)
            {
                SetJsonStatus(
                    $"INVALID Json format at (line {exception.LineNumber}, position {exception.LinePosition})",
                    true);
            }
            catch
            {
                SetJsonStatus("INVALID Json format", true);
            }
        }

        private void SetJsonStatus(string text, bool isError)
        {
            if (InvokeRequired)
            {
                //Invoke(new SetJsonStatusDelegate(SetActionStatus), text, isError);
                return;
            }

            jsonStatusLabel.Text = text;
            jsonStatusLabel.ForeColor = isError ? Color.OrangeRed : Color.Black;
        }

        private void jsonValueTextBox_Leave(object sender, EventArgs e)
        {
            jsonValueTextBox.TextChanged -= jsonValueTextBox_TextChanged;
        }

        private void jsonValueTextBox_Enter(object sender, EventArgs e)
        {
            jsonValueTextBox.TextChanged += jsonValueTextBox_TextChanged;
        }

        #region 状态条

        /// <summary>
        ///     输出状态信息
        /// </summary>
        /// <param name="msg"></param>
        private void ShowStatusMsg(string msg)
        {
            if (string.IsNullOrEmpty(msg)) return;
            MainForm mainForm = ParentForm as MainForm;
            mainForm?.ShowStatusMsg(msg);
        }

        #endregion

        #region 按钮

        private void btnLoadData_Click(object sender, EventArgs e)
        {
            using (new ControlAnimatorObject(btnLoadData))
            {
                //刷新代理对象
                RefreshProxy();
                //重置节点查询
                ResetTreeNodeQuery();
                //清空
                jsonValueTextBox.Text = string.Empty;
                //设置首节点为选中节点
                SetSelectedNodeWithTopNode();
                //输出状态信息
                ShowStatusMsg("重载数据成功");
            }
        }

        private void btnRefreshData_Click(object sender, EventArgs e)
        {
            using (new ControlAnimatorObject(btnRefreshData))
            {
                //重新加载代理对象
                ReLoadProxy();
                //重置节点查询
                ResetTreeNodeQuery();
                //清空
                int oldSelectionStart = jsonValueTextBox.SelectionStart;
                jsonValueTextBox.Text = string.Empty;
                //设置首节点为选中节点
                SetSelectedNodeWithTopNode();
                if (oldSelectionStart > 20)
                    oldSelectionStart -= 20;
                //滚动到修改位置
                jsonValueTextBox.SelectionStart = oldSelectionStart;
                jsonValueTextBox.ScrollToCaret();
                //输出状态信息
                ShowStatusMsg("累计重载数据成功");
            }
        }

        private void btnRunRequest_Click(object sender, EventArgs e)
        {
            using (new ControlAnimatorObject(btnRunRequest))
            {
                //执行代理请求
                ProxyTestDo();
            }
        }

        private void btnCopyRequestData_Click(object sender, EventArgs e)
        {
            using (new ControlAnimatorObject(btnRunRequest))
            {
                Dictionary<string, object> requestData = new Dictionary<string, object>();
                requestData.Add(ServiceHelper.ContextName, ContextInfo.GetContext());
                requestData.Add("proxy", GetProxyType());
                var jsonString = jTokenTree.jsonTreeView.Nodes[0].Tag.ToString();
                if (string.IsNullOrEmpty(jsonString))
                    jsonString = "{}";
                var jToken = JsonHelper.ObjectFromJsonString<JToken>(jsonString);
                requestData.Add("data", jToken);
                string requestJsonString = JsonHelper.ObjectToJsonString(requestData);
                Clipboard.SetDataObject(requestJsonString);
                //输出状态信息
                ShowStatusMsg("复制请求数据成功");
            }
        }

        #endregion

        #region 树查找

        private void jTokenTree_AfterSelect(object sender, AfterSelectEventArgs eventArgs)
        {
            //newtonsoftJsonTypeTextBox.Text = eventArgs.TypeName;
            //jsonTypeComboBox.Text = eventArgs.JTokenTypeName;
            // If jsonValueTextBox is focused then it triggers this event in the update process, so don't update it again ! (risk: infinite loop between events).
            if (!jsonValueTextBox.Focused)
            {
                jsonValueTabControl.SelectedIndex = 0;
                jsonValueTextBox.Text = eventArgs.GetJsonString();
            }
        }

        private void txtNodeQueryString_TextChanged(object sender, EventArgs e)
        {
            _currTreeNodeLinklist = null;
        }

        private void txtNodeQueryString_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                btnTreeNodeFind_Click(sender, e);
            }
        }

        private void btnTreeNodeFind_Click(object sender, EventArgs e)
        {
            var queryString = txtNodeQueryString.Text;
            if (string.IsNullOrWhiteSpace(queryString)) return;
            bool isLikeLookup = chkLikeLookup.Checked;
            _currTreeNodeLinklist = null;
            var queryResultNodes = new List<TreeNode>();
            //查找
            FindJsonTreeNode(queryString, isLikeLookup, ref queryResultNodes);
            btnTreeNodeFind.Text = string.Format("查 找({0})", queryResultNodes.Count);
            if (queryResultNodes.Count > 0)
            {
                if (chkLevelPriority.Checked)
                    SortTreeNodeByLevel(ref queryResultNodes);
                TreeNodeLinkList currLinklist = null;
                foreach (var treeNode in queryResultNodes)
                {
                    var tmpLinklist = new TreeNodeLinkList();
                    tmpLinklist.TreeNode = treeNode;
                    if (currLinklist != null)
                    {
                        currLinklist.Down = tmpLinklist;
                    }

                    tmpLinklist.Up = currLinklist;
                    if (_currTreeNodeLinklist == null)
                        _currTreeNodeLinklist = tmpLinklist;
                    currLinklist = tmpLinklist;
                }

                if (_currTreeNodeLinklist != null)
                {
                    jTokenTree.jsonTreeView.Focus();
                    jTokenTree.jsonTreeView.SelectedNode = _currTreeNodeLinklist.TreeNode;
                }
            }

            //设置查询按钮状态
            SetQueryButtonStatus();
        }

        private void btnTreeNodeDown_Click(object sender, EventArgs e)
        {
            if (_currTreeNodeLinklist == null)
            {
                btnTreeNodeFind_Click(btnTreeNodeFind, e);
            }
            else
            {
                if (_currTreeNodeLinklist.Down != null)
                {
                    _currTreeNodeLinklist = _currTreeNodeLinklist.Down;
                    jTokenTree.jsonTreeView.Focus();
                    jTokenTree.jsonTreeView.SelectedNode = _currTreeNodeLinklist.TreeNode;
                    //设置查询按钮状态
                    SetQueryButtonStatus();
                }
            }
        }

        private void btnTreeNodeUp_Click(object sender, EventArgs e)
        {
            if (_currTreeNodeLinklist == null)
            {
                btnTreeNodeFind_Click(btnTreeNodeFind, e);
            }
            else
            {
                if (_currTreeNodeLinklist.Up != null)
                {
                    _currTreeNodeLinklist = _currTreeNodeLinklist.Up;
                    jTokenTree.jsonTreeView.Focus();
                    jTokenTree.jsonTreeView.SelectedNode = _currTreeNodeLinklist.TreeNode;
                    //设置查询按钮状态
                    SetQueryButtonStatus();
                }
            }
        }

        /// <summary>
        ///     查询Json树
        /// </summary>
        /// <param name="queryString"></param>
        /// <param name="isLikeLookup"></param>
        /// <param name="queryResultNodes"></param>
        private void FindJsonTreeNode(string queryString, bool isLikeLookup, ref List<TreeNode> queryResultNodes)
        {
            if (string.IsNullOrEmpty(queryString)) return;
            queryString = queryString.ToLower();
            foreach (TreeNode node in jTokenTree.jsonTreeView.Nodes)
            {
                if (node.Nodes.Count == 0) continue;
                var jsonPropertyName = node.Text.ToLower();
                if (!jsonPropertyName.StartsWith("{") && !jsonPropertyName.StartsWith("["))
                {
                    var index = jsonPropertyName.IndexOf(":", 0, StringComparison.CurrentCultureIgnoreCase);
                    if (index > 2)
                    {
                        jsonPropertyName = jsonPropertyName.Substring(1, index - 2);
                    }

                    if (isLikeLookup)
                    {
                        if (jsonPropertyName.IndexOf(queryString, StringComparison.CurrentCultureIgnoreCase) >= 0)
                            queryResultNodes.Add(node);
                    }
                    else
                    {
                        if (jsonPropertyName == queryString) queryResultNodes.Add(node);
                    }
                }

                if (node.Nodes.Count == 0) continue;
                //查找子节点
                FindChildTreeNode(node, queryString, isLikeLookup, ref queryResultNodes);
            }
        }

        /// <summary>
        ///     查找子节点
        /// </summary>
        /// <param name="parentTreeNode"></param>
        /// <param name="queryString"></param>
        /// <param name="isLikeLookup"></param>
        /// <param name="queryResultNodes"></param>
        private void FindChildTreeNode(TreeNode parentTreeNode, string queryString, bool isLikeLookup,
            ref List<TreeNode> queryResultNodes)
        {
            if (string.IsNullOrEmpty(queryString)) return;
            foreach (TreeNode node in parentTreeNode.Nodes)
            {
                if (node.Nodes.Count == 0) continue;
                var jsonPropertyName = node.Text.ToLower();
                if (!jsonPropertyName.StartsWith("{") && !jsonPropertyName.StartsWith("["))
                {
                    var index = jsonPropertyName.IndexOf(":", 0, StringComparison.CurrentCultureIgnoreCase);
                    if (index > 2)
                    {
                        jsonPropertyName = jsonPropertyName.Substring(1, index - 2);
                    }

                    if (isLikeLookup)
                    {
                        if (jsonPropertyName.IndexOf(queryString, StringComparison.CurrentCultureIgnoreCase) >= 0)
                            queryResultNodes.Add(node);
                    }
                    else
                    {
                        if (jsonPropertyName == queryString) queryResultNodes.Add(node);
                    }
                }

                if (node.Nodes.Count == 0) continue;
                //查找子节点
                FindChildTreeNode(node, queryString, isLikeLookup, ref queryResultNodes);
            }
        }

        /// <summary>
        ///     排序
        /// </summary>
        /// <param name="queryResultNodes"></param>
        private void SortTreeNodeByLevel(ref List<TreeNode> queryResultNodes)
        {
            var levelList = new List<int>();
            var dict = new Dictionary<int, List<TreeNode>>();
            foreach (var treeNode in queryResultNodes)
            {
                if (!dict.ContainsKey(treeNode.Level))
                {
                    levelList.Add(treeNode.Level);
                    dict.Add(treeNode.Level, new List<TreeNode>());
                }

                dict[treeNode.Level].Add(treeNode);
            }

            levelList.Sort();
            queryResultNodes = new List<TreeNode>();
            foreach (var level in levelList)
            {
                queryResultNodes.AddRange(dict[level]);
            }
        }

        /// <summary>
        ///     重置节点查询
        /// </summary>
        private void ResetTreeNodeQuery()
        {
            _currTreeNodeLinklist = null;
            btnTreeNodeFind.Text = btnTreeNodeFind.Text = string.Format("查 找({0})", 0);
            //设置查询按钮状态
            SetQueryButtonStatus();
        }

        /// <summary>
        ///     设置查询按钮状态
        /// </summary>
        private void SetQueryButtonStatus()
        {
            if (_currTreeNodeLinklist == null)
            {
                btnTreeNodeDown.Enabled = false;
                btnTreeNodeUp.Enabled = false;
            }
            else
            {
                btnTreeNodeDown.Enabled = _currTreeNodeLinklist.Down != null;
                btnTreeNodeUp.Enabled = _currTreeNodeLinklist.Up != null;
            }
        }

        /// <summary>
        ///     设置首节点为选中节点
        /// </summary>
        private void SetSelectedNodeWithTopNode()
        {
            if (jTokenTree.jsonTreeView.Nodes.Count <= 0) return;
            var topNode = jTokenTree.jsonTreeView.Nodes[0];
            jTokenTree.jsonTreeView.SelectedNode = topNode;
            topNode.Expand();
        }

        #endregion

        #region 事务调试

        /// <summary>
        ///     代理事务调试
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void chkSetupProxyTypeTransactionDebug_CheckedChanged(object sender, EventArgs e)
        {
            string u9URI = SettingManagement.Instance.Setting.U9URI;
            string proxyType = GetProxyType();
            if (string.IsNullOrEmpty(proxyType)) throw new ProxyToolException("代理类型不能为空");
            if (chkSetupProxyTypeTransactionDebug.Checked)
            {
                if (DebugService.SetupTransactionDebug(u9URI, 1, proxyType))
                    ShowStatusMsg("开启代理事务日志成功");
            }
            else
            {
                if (DebugService.StopTransactionDebug(u9URI, 1, proxyType))
                    ShowStatusMsg("关闭代理事务日志成功");
            }
        }

        /// <summary>
        ///     全局事务调试
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void chkSetupGlobalTransactionDebug_CheckedChanged(object sender, EventArgs e)
        {
            string u9URI = SettingManagement.Instance.Setting.U9URI;
            if (chkSetupGlobalTransactionDebug.Checked)
            {
                if (DebugService.SetupTransactionDebug(u9URI, 0))
                    ShowStatusMsg("开启全局事务日志成功");
            }
            else
            {
                if (DebugService.StopTransactionDebug(u9URI, 0))
                    ShowStatusMsg("关闭全局事务日志成功");
            }
        }

        /// <summary>
        ///     输出代理日志
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void chkOutputProxyDoLog_CheckedChanged(object sender, EventArgs e)
        {
            string u9URI = SettingManagement.Instance.Setting.U9URI;
            string proxyType = GetProxyType();
            if (string.IsNullOrEmpty(proxyType)) throw new ProxyToolException("代理类型不能为空");
            if (chkOutputProxyDoLog.Checked)
            {
                if (DebugService.SetupProxyDoDebug(u9URI, proxyType))
                    ShowStatusMsg("开启输出代理日志成功");
            }
            else
            {
                if (DebugService.StopProxyDoDebug(u9URI, proxyType))
                    ShowStatusMsg("关闭输出代理日志成功");
            }
        }

        /// <summary>
        ///     初始化调试
        /// </summary>
        private void InitDebug()
        {
            chkSetupProxyTypeTransactionDebug.Checked = false;
            chkSetupGlobalTransactionDebug.Checked = false;
            chkOutputProxyDoLog.Checked = false;
            string u9URI = SettingManagement.Instance.Setting.U9URI;
            bool isEnableDebug = !string.IsNullOrEmpty(u9URI) && SettingManagement.Instance.IsSupportDebug;
            chkSetupProxyTypeTransactionDebug.Enabled = isEnableDebug;
            chkSetupGlobalTransactionDebug.Enabled = isEnableDebug;
            chkOutputProxyDoLog.Enabled = isEnableDebug;
            if (!isEnableDebug) return;
            chkSetupGlobalTransactionDebug.Checked = DebugService.IsTransactionDebugging(u9URI, 0);
            string proxyType = GetProxyType();
            if (!string.IsNullOrEmpty(proxyType))
            {
                chkSetupProxyTypeTransactionDebug.Checked =
                    DebugService.IsTransactionDebugging(u9URI, 1, proxyType);
                chkOutputProxyDoLog.Checked = DebugService.IsProxyDoDebugging(u9URI, proxyType);
            }

            chkSetupProxyTypeTransactionDebug.CheckedChanged += chkSetupProxyTypeTransactionDebug_CheckedChanged;
            chkSetupGlobalTransactionDebug.CheckedChanged += chkSetupGlobalTransactionDebug_CheckedChanged;
            chkOutputProxyDoLog.CheckedChanged += chkOutputProxyDoLog_CheckedChanged;
        }

        /// <summary>
        ///     停止代理调试
        /// </summary>
        internal void StopProxyTypeDebug()
        {
            string u9URI = SettingManagement.Instance.Setting.U9URI;
            if (string.IsNullOrEmpty(u9URI)) return;
            string proxyType = GetProxyType();
            if (string.IsNullOrEmpty(proxyType)) return;
            if (chkSetupProxyTypeTransactionDebug.Checked)
            {
                Task.Run(() =>
                {
                    try
                    {
                        DebugService.StopTransactionDebug(u9URI, 1, proxyType);
                    }
                    catch (Exception ex)
                    {
                    }
                });
            }

            if (chkOutputProxyDoLog.Checked)
            {
                Task.Run(() =>
                {
                    try
                    {
                        DebugService.StopProxyDoDebug(u9URI, proxyType);
                    }
                    catch (Exception ex)
                    {
                    }
                });
            }
        }

        #endregion
    }
}